package com.lzy.cloud.payment.component.pay;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeFastpayRefundQueryModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.lzy.cloud.payment.constants.BusinessStatus;
import com.lzy.cloud.payment.constants.CommonConstants;
import com.lzy.cloud.payment.dtos.pay.*;
import com.lzy.cloud.payment.dtos.payment.PayBillDto;
import com.lzy.cloud.payment.dtos.payment.PayInfoDto;
import com.lzy.cloud.payment.dtos.payment.PayRefundInfoDto;
import com.lzy.cloud.payment.entity.PayRefundInfo;
import com.lzy.cloud.payment.pay.alipay.AlipayConfig;
import com.lzy.cloud.payment.pay.alipay.AlipayCore;
import com.lzy.cloud.payment.pay.alipay.UtilDate;
import com.lzy.cloud.payment.pay.weixin.WxPayData;
import com.lzy.cloud.payment.remote.OrderApi;
import com.lzy.cloud.payment.remote.RabbitmqApi;
import com.lzy.cloud.payment.service.PayBillService;
import com.lzy.cloud.payment.service.PayInfoService;
import com.lzy.cloud.payment.service.PayRefundInfoService;
import com.lzy.cloud.payment.utils.Common;
import com.lzy.cloud.payment.utils.FileUtil;
import com.lzy.cloud.payment.utils.StringUtil;
import com.lzy.framework.core.ensure.Ensure;
import com.lzy.framework.core.utils.DateUtil;
import com.lzy.framework.core.utils.DozerUtils;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;

@Component("alipay/commons")
public  class AlipayPayCommons extends PayCommons<AlipayPayDTO> {

	private static final Logger logger = LoggerFactory.getLogger(AlipayPayCommons.class);

	@Autowired
	private PayBillService payBillService;

	@Autowired
	private PayRefundInfoService payRefundInfoSerice;

	@Autowired
	private OrderApi orderApi;

	@Autowired
	private PayInfoService payInfoService;

	@Autowired
	private RabbitmqApi rabbitmqApi;

	@Override
	public String payAsyNotify(AlipayPayDTO apDTO) {
		String result = CommonConstants.FAIL;
		Map<String,String> params = null;
		//将实体类转化成map
		try {
			params = Common.convertBean(apDTO);
			params.remove("way");
		} catch (Exception e) {
			logger.info("-----实体转化Map异常------"+e);
		}
		//获取待验签合法
		boolean verify_result;
		try {
			params = AlipayCore.paraFilter(params);  //将空字符串去除
			logger.info("-------支付宝请求参数------"+params.toString());
			verify_result = AlipaySignature.rsaCheckV1(params, new FileUtil().getResources(AlipayConfig.ALIPAY_PUBLIC_KEY), AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);
			//签名成功
			if(verify_result){
				BasePayDTO basePayDTO = new BasePayDTO();
				basePayDTO.setOut_trade_no(apDTO.getOut_trade_no());
				basePayDTO.setWay(apDTO.getWay());
				basePayDTO.setUserId(apDTO.getUserId());
				basePayDTO.setSign(apDTO.getSign());
				basePayDTO.setType(apDTO.getType());
				basePayDTO.setId(apDTO.getId());
				PayBackDTO payBackDTO = new PayBackDTO();
				payBackDTO.setParams(params);
				payBackDTO.setBasePayDTO(basePayDTO);
				result = DozerUtils.map(rabbitmqApi.paymentProcessing(payBackDTO).getResult(),String.class);
				if(!StringUtil.isNullOrEmpty(result)){
					return result;
				}
			}else{
				return result;
			}
		} catch (AlipayApiException e) {
			logger.info("-----调用支付宝第三方SDk验签异常-----"+e);
			Ensure.that(true).isTrue("09000017");
		}
		return result;
	}
	/**
	 * 支付宝请求签名
	 * @param commonPayDTO
	 * @return
	 * @throws Exception
	 */
	public Map<String,Object> prepayOrder(CommonPayDTO commonPayDTO) {
		Map<String,Object>  responseData = new HashMap<String,Object>();
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,AlipayConfig.APPID,new FileUtil().getResources(AlipayConfig.RSA_PRIVATE_KEY),AlipayConfig.FORMAT,AlipayConfig.CHARSET,new FileUtil().getResources(AlipayConfig.ALIPAY_PUBLIC_KEY),AlipayConfig.SIGNTYPE);
		//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
		//SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的m odel入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
		model.setSubject(String.valueOf(commonPayDTO.getSkuName()));
		model.setBody(String.valueOf(commonPayDTO.getSkuName()));
		model.setOutTradeNo(String.valueOf(commonPayDTO.getSerialNumber()));
		model.setTimeoutExpress("30m");   //订单默认失效时间30分钟
		model.setTotalAmount(String.valueOf(commonPayDTO.getAmount()));
		model.setProductCode("QUICK_MSECURITY_PAY");
		request.setBizModel(model);
		request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
		try {
	        //这里和普通的接口调用不同，使用的是sdkExecute
	        AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
	        logger.info("----支付宝预付订单签名---="+response.getBody());   //就是orderString 可以直接给客户端请求，无需再做处理。
	        responseData.put("sign", response.getBody());
		} catch (AlipayApiException e) {
		    e.printStackTrace();
		}
		return responseData;
	}

	/**
	 * 扫码支付宝请求签名
	 * @param commonPayDTO
	 * @return
	 * @throws Exception
	 */
	public Map<String,Object> scanCodePayPrepayOrder(CommonPayDTO commonPayDTO) {
		Map<String,Object>  responseData = new HashMap<String,Object>();
		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,AlipayConfig.APPID,new FileUtil().getResources(AlipayConfig.RSA_PRIVATE_KEY),AlipayConfig.FORMAT,AlipayConfig.CHARSET,new FileUtil().getResources(AlipayConfig.ALIPAY_PUBLIC_KEY),AlipayConfig.SIGNTYPE);
		//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
		AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
		//SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的m odel入参方式(model和biz_content同时存在的情况下取biz_content)。
		AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
		model.setSubject(String.valueOf(commonPayDTO.getSkuName()));
		model.setBody(String.valueOf(commonPayDTO.getSkuName()));
		model.setOutTradeNo(String.valueOf(commonPayDTO.getSerialNumber()));
		model.setTimeoutExpress("2160m");   //订单默认失效时间30分钟
		model.setTotalAmount(String.valueOf(commonPayDTO.getAmount()));
		request.setBizModel(model);
		request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
		//request.setReturnUrl(a);
		try {
			//这里和普通的接口调用不同，使用的是sdkExecute
			AlipayTradePrecreateResponse response = alipayClient.execute(request);
			logger.info("----支付宝预付订单签名---="+response.getBody());   //就是orderString 可以直接给客户端请求，无需再做处理。
			responseData.put("code_url", response.getQrCode());
		} catch (AlipayApiException e) {
			e.printStackTrace();
		}
		return responseData;
	}
	/**
	 * 支付宝退款接口
	 * @param mqDTO
	 * @return
	 * @throws AlipayApiException
	 */
	public Map<String,Object> applyAlipayPayRefund(MobileRequestDTO mqDTO) throws Exception{
		WxPayData data = new WxPayData();
        data.put("app_id", AlipayConfig.APPID);     //支付宝分配的商户号
        data.put("method",CommonConstants.METHOD);  //接口名称
        data.put("charset", AlipayConfig.CHARSET);  //请求编码
        data.put("sign_type", AlipayConfig.SIGNTYPE);  //签名方式
        data.put("timestamp", UtilDate.getDateFormatter()); //请求时间
		data.put("version", "1.0");

		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,AlipayConfig.APPID,new FileUtil().getResources(AlipayConfig.RSA_PRIVATE_KEY),data.toJson(),AlipayConfig.CHARSET,new FileUtil().getResources(AlipayConfig.ALIPAY_PUBLIC_KEY),AlipayConfig.SIGNTYPE);
		AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
		AlipayTradeRefundModel model = new AlipayTradeRefundModel();
		model.setOutTradeNo(String.valueOf(mqDTO.getOrderId()));
		model.setRefundAmount(mqDTO.getRefundAmount());
		//部分退款
		if(mqDTO.getAmount().compareTo(mqDTO.getRefundAmount()) != 0){
			model.setOutRequestNo(String.valueOf(mqDTO.getRefundNumber()));  //本地退款订单号
		}
		request.setBizModel(model);
		AlipayTradeRefundResponse response = alipayClient.execute(request);
		logger.info("----支付宝响应---code="+response.getCode()+",-----msg="+response.getMsg());
		logger.info("---支付宝返回退款结果---"+response.getBody());
		WxPayData resultParams = new WxPayData();
		if(response.isSuccess()){
			JSONObject jsonObj = new JSONObject(response.getBody());
			Map<String,String> params = Common.jsonToObject(jsonObj.get("alipay_trade_refund_response").toString());

			//更新退款表    payRefundInfo    (支付宝没有退款单号)
			PayRefundInfoDto priDO = new PayRefundInfoDto();
			priDO.setId(Long.valueOf(mqDTO.getId()));
			//退款中
			if(params.get("code").equals("10000")){
				/*SimpleDateFormat sdf  =  new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				priDO.setSuccesTime(sdf.parse(String.valueOf(params.get("gmt_refund_pay")))); //退款支付时间
*/				priDO.setThirdNumber(params.get("trade_no"));
				priDO.setStatus(CommonConstants.PayRefundStatus.DISPOSE.getIndex());
				resultParams.put("status", CommonConstants.PayRefundStatus.DISPOSE.getIndex());  //退款中
				logger.info("---订单退款结束---");
			//退款失败	--1.客户端重新发起请求   2.后台商家客服人工发起请求退款
			}else{
				//更新订单状态
				executeRefund(mqDTO.getOrderId(),3);
				priDO.setStatus(CommonConstants.PayRefundStatus.UNUSUAL.getIndex());
				resultParams.put("status", CommonConstants.PayRefundStatus.UNUSUAL.getIndex());  //退款失败
				logger.info("退款失败:"+params.get("sub_msg"));
			}
			int count = payRefundInfoSerice.updatePayRefundInfo(priDO);
			Ensure.that(count > 0).isTrue("09000070");
		} else {
			logger.info("-----支付宝网络异常调用失败---");
			Ensure.that(true).isTrue("09000010");
		}
		return resultParams.toMap();
	}
	/**
	 * 支付宝退款查询
	 * @param payRefundInfo
	 * @throws Exception
	 */
	public void applyAlipayPayRefundQuery(PayRefundInfo payRefundInfo) throws Exception{
		logger.info("-----退款查询开始-------订单号:"+payRefundInfo.getOrderId());
		WxPayData data = new WxPayData();
        data.put("app_id", AlipayConfig.APPID);           //支付宝分配的商户号
        data.put("method", CommonConstants.METHOD_QUERY); //接口名称
        data.put("charset", AlipayConfig.CHARSET);        //请求编码
        data.put("sign_type", AlipayConfig.SIGNTYPE);     //签名方式
        data.put("timestamp", UtilDate.getDateFormatter()); //请求时间
		data.put("version", "1.0");

		AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL,AlipayConfig.APPID,new FileUtil().getResources(AlipayConfig.RSA_PRIVATE_KEY),data.toJson(),AlipayConfig.CHARSET,new FileUtil().getResources(AlipayConfig.ALIPAY_PUBLIC_KEY),AlipayConfig.SIGNTYPE);
		AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
		AlipayTradeFastpayRefundQueryModel model = new AlipayTradeFastpayRefundQueryModel();
		model.setOutTradeNo(String.valueOf(payRefundInfo.getOrderId()));
		if(payRefundInfo.getAmount().compareTo(payRefundInfo.getRefundAmount()) == 0){
			//全额退款
			model.setOutRequestNo(String.valueOf(payRefundInfo.getOrderId()));  //本地交易订单号
		}else{
			//部分退款
			model.setOutRequestNo(String.valueOf(payRefundInfo.getRefundNumber()));  //本地退款单号
		}
		request.setBizModel(model);
		AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
		logger.info("---支付宝返回退款查询结果---"+response.getBody());

		if(response.isSuccess()){
			JSONObject jsonObj = new JSONObject(response.getBody());
			Map<String,String> params = Common.jsonToObject(jsonObj.get("alipay_trade_fastpay_refund_query_response").toString());
			params.put("sign", jsonObj.getString("sign"));
				//退款成功
				if(params.get("code").equals("10000") && params.containsKey("out_trade_no")){
					//更新退款表    payRefundInfo
					PayRefundInfoDto priDO = new PayRefundInfoDto();
					priDO.setId(payRefundInfo.getId());
					priDO.setStatus(CommonConstants.PayRefundStatus.SUCCESS.getIndex());   //退款状态
					priDO.setUpdateTime(DateUtil.format(new Date()));  //更新时间
					priDO.setSuccessTime(DateUtil.format(new Date()));  //退款成功时间
					payRefundInfoSerice.updatePayRefundInfo(priDO);

					//更新订单状态
					executeRefund(payRefundInfo.getOrderId(),1);

					//新增支付账单表   payBill
					PayBillDto pbDO = PayBillDto.convert(payRefundInfo);
					payBillService.createPayBill(pbDO);
					logger.info("---查询订单退款结束---订单号:"+payRefundInfo.getOrderId());
				}
				//退款失败人工处理
		}else{
			logger.info("-----支付宝网络异常调用失败---");
			Ensure.that(true).isTrue("09000010");
		}

	}
	/**
	 * 支付宝BizContent参数配置
	 * @param mqDTO
	 * @return
	 */
	public Map<String,Object> alipayBizContent(MobileRequestDTO mqDTO){
		Map<String,Object> map = new HashMap<String,Object>();
		map.put("subject", "test");
		map.put("out_trade_no", mqDTO.getPayOrderDTO().getOrderId()+"");
		map.put("total_amount", "0.01");
		map.put("product_code", CommonConstants.PRODUCT_CODE);
		map.put("timeout_express", "30m"); //设置订单失效时间 30分钟
		return sortMapByKey(map);
	}

	/**
	 * 退款--处理各种退款信息
	 * @param serialNumber  订单号
	 * @param type 退款类型  1：标识退款成功   3:表示退款异常（失败）
	 * @return
	 */
	public void executeRefund(String serialNumber,int type){
		//获取支付类型
		PayInfoDto payInfoDO = payInfoService.queryPayInfoByOrderId(serialNumber);
		switch (payInfoDO.getType()){
			case BusinessStatus.PayInfoType.pay:
				executePayRefund(serialNumber,type);
				break;
		}
	}

	/**
	 * 内部订单
	 * @param serialNumber  订单号
	 * @param type 退款类型  1：标识退款成功   3:表示退款异常（失败）
	 * @return
	 */
	public void executePayRefund(String serialNumber,int type){
		PayOrderParamsDTO paramsDTO = new PayOrderParamsDTO();
		paramsDTO.setOrderId(serialNumber);
		if(type == 1){
			paramsDTO.setStutas(CommonConstants.PayRefundStatus.SUCCESS.getIndex());
		}else{
			paramsDTO.setStutas(2);
		}

		boolean count = DozerUtils.map(orderApi.updatePayOrderStatus(paramsDTO).getResult(),Boolean.class);
		logger.info("----------退款处理订单号="+serialNumber+",-----订单更新返回结果="+count);
		//Ensure.that(count).isTrue("09000071");
	}

	/**
     * 使用 Map按key进行排序
     * @param map
     * @return
     */
    public static Map<String, Object> sortMapByKey(Map<String, Object> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<String, Object> sortMap = new TreeMap<String, Object>(new MapKeyComparator());
        sortMap.putAll(map);
		return sortMap;
    }
	 static String JSONObject = "{\"out_trade_no\":405231019919283,\"total_amount\":1060,\"subject\":\"浙江龙之游旅游开发有限公司\",\"product_code\":\"QUICK_MSECURITY_PAY\"}" ;
	    public static void main(String[] args) {
	        try {
	            JSONObject jsonObject = new JSONObject(JSONObject);
	            System.out.println(jsonObject.toString());
	            System.out.println(jsonObject.get("out_trade_no"));
	        } catch (JSONException e) {
	            // TODO Auto-generated catch block
	            e.printStackTrace();
	        }

	    }
}

class MapKeyComparator implements Comparator<String>{
	public int compare(String str1, String str2) {
		return str1.compareTo(str2);
	}
}